//#define _CRTDBG_MAP_ALLOC
#include "StdAfx.h"
#include "Frame.h"
//#define _CRTDBG_MAP_ALLOC


Frame::Frame(void)
{
    this->histogram = NULL;
    this->image = NULL;
    this->grayImage = NULL;
}
void Frame::setFrameNo(int frameNo){
    this->frameNo = frameNo;
    /*outPutFile.open ("output\\output.txt", ios::app);
    outPutFile<<frameNo<<endl;
    outPutFile.close();*/
}

int Frame::getFrameNo(){
    return this->frameNo;
}
void Frame::setFileName(string fileName){
    this->fileName = fileName;
}

string Frame::getFileName(){
    return this->fileName;
}

void Frame::setFrame(IplImage *image){
    
    this->grayImage=0;
    if(image!=0)
    {
        this->image = image;
        this->grayImage=cvCreateImage(cvGetSize(this->image),IPL_DEPTH_8U,1);
        cvCvtColor(this->image,this->grayImage,CV_RGB2GRAY);
    }

}
IplImage* Frame::getFrame(){

    return this->image;
}
IplImage* Frame::getGrayFrame(){
    return this->grayImage;
}
double Frame::getThreshVal_Otsu( const CvHistogram* hist )
{
    double max_val = 0;

    CV_FUNCNAME( "getThreshVal_Otsu" );

    //    __BEGIN__;

    int i, count;
    const float* h;
    double sum = 0, mu = 0;
    bool uniform = false;
    double low = 0, high = 0, delta = 0;
    float* nu_thresh = 0;
    double mu1 = 0, q1 = 0;
    double max_sigma = 0;

    /* if( !CV_IS_HIST(hist) || CV_IS_SPARSE_HIST(hist) || hist->mat.dims != 1 )
    CV_ERROR( CV_StsBadArg,"The histogram in Otsu method must be a valid dense 1D histogram" );*/

    count = hist->mat.dim[0].size;
    h = (float*)cvPtr1D( hist->bins, 0 );

    if( !CV_HIST_HAS_RANGES(hist) || CV_IS_UNIFORM_HIST(hist) )
    {
        if( CV_HIST_HAS_RANGES(hist) )
        {
            low = hist->thresh[0][0];
            high = hist->thresh[0][1];
        }
        else
        {
            low = 0;
            high = count;
        }

        delta = (high-low)/count;
        low += delta*0.5;
        uniform = true;
    }
    else
        nu_thresh = hist->thresh2[0];

    for( i = 0; i < count; i++ )
    {
        sum += h[i];
        if( uniform )
            mu += (i*delta + low)*h[i];
        else
            mu += (nu_thresh[i*2] + nu_thresh[i*2+1])*0.5*h[i];
    }

    sum = fabs(sum) > FLT_EPSILON ? 1./sum : 0;
    mu *= sum;

    mu1 = 0;
    q1 = 0;

    for( i = 0; i < count; i++ )
    {
        double p_i, q2, mu2, val_i, sigma;

        p_i = h[i]*sum;
        mu1 *= q1;
        q1 += p_i;
        q2 = 1. - q1;

        if( MIN(q1,q2) < FLT_EPSILON || MAX(q1,q2) > 1. - FLT_EPSILON )
            continue;

        if( uniform )
            val_i = i*delta + low;
        else
            val_i = (nu_thresh[i*2] + nu_thresh[i*2+1])*0.5;

        mu1 = (mu1 + val_i*p_i)/q1;
        mu2 = (mu - q1*mu1)/q2;
        sigma = q1*q2*(mu1 - mu2)*(mu1 - mu2);
        if( sigma > max_sigma )
        {
            max_sigma = sigma;
            max_val = val_i;
        }
    }

    // __END__;

    return max_val;
}
//int Frame::getOptimumThreshold(IplImage* imageGrayScale){
int Frame::getOptimumThreshold()
{
    IplImage* imageGrayScale = cvCreateImage( cvSize(this->image->width, this->image->height), IPL_DEPTH_8U, 1);
    cvCvtColor(this->image, imageGrayScale, CV_BGR2GRAY);


    CvHistogram* histThreshold = 0;
    int coi1 = 0;	

    CvMat src_stub, *src = (CvMat*)imageGrayScale;  //srcarr - IplImage
    CvMat src0;
    src = cvGetMat( src, &src_stub, &coi1 );


    if(CV_MAT_CN(src->type)>1){
        src = cvReshape(src,&src0,1);	
    }

    float _ranges[] = { 0, 256 };
    float* ranges = _ranges;
    int hist_size = 256;
    void* srcarr0 = src;

    int optimumThreshold=60;
    if(CV_MAT_TYPE(src->type) != CV_8UC1 ){
        printf("Otsu method can only be used with 8uC1 images");
    }else{
        histThreshold = cvCreateHist( 1, &hist_size, CV_HIST_ARRAY, &ranges );
        cvCalcArrHist( &srcarr0, histThreshold );
        //optimumThreshold = cvFloor(getThreshVal_Otsu( histThreshold )*0.35); // was 0.7
        optimumThreshold = cvFloor(getThreshVal_Otsu( histThreshold )*0.35); // was 0.5
    }        
    cvReleaseHist(&histThreshold);
    cvReleaseImage(&imageGrayScale);
    return optimumThreshold;
}

 void Frame::setTime(time_t time)
 {
    this->time=time;
 }
 time_t Frame::getTime()
 {
     return time; 
 }
 
CvSize Frame::getFrameSize()
{
    return cvSize(this->image->width,this->image->height);
}
IplImage* Frame::getLicensePlate()
{
    return 0;
}
//Creats and set the Histogram
CvHistogram* Frame::getHistogram()
{

    IplImage* ch1 = cvCreateImage( cvGetSize(this->image), 8, 1);
    IplImage* ch2 = cvCreateImage( cvGetSize(this->image), 8, 1);
    IplImage* ch3 = cvCreateImage( cvGetSize(this->image), 8, 1);
    IplImage* planes[] = {ch1, ch2, ch3};

    int hdimsArr[] = {COLOR_HIST_DIMENTION_LENGTH, COLOR_HIST_DIMENTION_LENGTH, COLOR_HIST_DIMENTION_LENGTH};	
    float** hdimRanges = new float*[3];

    for(int i = 0; i < 3; i++){
        float tmpArr[] = {COLOR_HIST_MIN_VALUE, COLOR_HIST_MAX_VALUE};			   
        hdimRanges[i] = tmpArr;
    }
    this->histogram = cvCreateHist( 3, hdimsArr, CV_HIST_ARRAY, hdimRanges, 1 );

    cvSplit(this->image, ch1, ch2, ch3,0);
    cvCalcHist(planes, this->histogram, 0, 0);

    return this->histogram;
}
//Creats and set the Signature
CvMat* Frame::getSignature()
{
    int bins = COLOR_HIST_DIMENTION_LENGTH;
    int numrows = bins*bins*bins;
    this->signature=cvCreateMat(numrows, 4, CV_32FC1);   // rows, columns was 3 in HSV, type
    
    for( int r = 0; r < COLOR_HIST_DIMENTION_LENGTH; r++ )
    {
        for( int g = 0; g < COLOR_HIST_DIMENTION_LENGTH; g++ )
        {
            for ( int b = 0; b < COLOR_HIST_DIMENTION_LENGTH; b++ )
            { 
                float bin_val = cvQueryHistValue_3D( this->histogram, r, g, b );
                cvSet2D( this->signature, r * bins * bins + g * bins + b, 0, cvScalar(bin_val)); //bin value
                cvSet2D( this->signature, r * bins * bins + g * bins + b, 1, cvScalar(r)); //Coord 1
                cvSet2D( this->signature, r * bins * bins + g * bins + b, 2, cvScalar(g)); //Coord 2
                cvSet2D( this->signature, r * bins * bins + g * bins + b, 3, cvScalar(b)); //Coord 3 
            }
        }
    }
/*
    for( int h = 0; h < h_bins; h++ ) {
        for( int s = 0; s < s_bins; s++ ) {
            float bin_val = cvQueryHistValue_2D( hist1, h, s );
            cvSet2D(this->signature,h*s_bins + s,0,cvScalar(bin_val)); //bin value
            cvSet2D(this->signature,h*s_bins + s,1,cvScalar(h)); //Coord 1
            cvSet2D(this->signature,h*s_bins + s,2,cvScalar(s)); //Coord 2
        }
    }*/

    return this->signature;
}


void Frame::showFrame(IplImage* image){
    /* create a window */
    cvNamedWindow( "Frame", CV_WINDOW_AUTOSIZE );	
    /* display the image */
    cvShowImage( "Frame",image);
    /* wait until user press a key */
    cvWaitKey(0);	
    /* free memory */
    cvDestroyWindow( "Frame" );
}

Frame::~Frame(void)
{
	if(this->histogram != NULL){
		cvReleaseHist(& this->histogram);
	}
	//if(image != NULL){
	if(this->image != NULL){
		cvReleaseImage(& this->image);
	}
	if(this->grayImage != NULL){
		cvReleaseImage(& this->grayImage);
	}
	if(this->signature != NULL){
		 //cvReleaseMat(& this->signature);
	}
}
